package yxy.game.pm2.bean;

import org.redisson.api.RSet;
import yxy.apple.util.redisson.RedisException;
import yxy.cherry.game.base.redis.RedisManager;
import yxy.game.pm2.bean.currency.CurrencyGroup;
import yxy.game.pm2.bean.currency.CurrencyNotEnoughException;
import yxy.game.pm2.bean.currency.CurrencyType;
import yxy.game.pm2.bean.db.newDao.SignDAO;
import yxy.game.pm2.bean.db.po.SignPo;
import yxy.game.pm2.bean.module.BaseGameRedisLockBean;

import java.util.*;

import static yxy.apple.util.StringTrans.set2String;
import static yxy.apple.util.StringTrans.string2Set;

public class Sign extends BaseGameRedisLockBean {
	// redis==========================================================================

	static public String key(String playerCode, CurrencyType type) {
		return String.format("PLAYER:%s:SIGN:%d", playerCode, type.getNumber());
	}
	static private RSet<String> touch(String key) throws RedisException {
		return RedisManager.client(redis()).getSet(key);
	}
	public static void init (String playerCode) {
		ArrayList<CurrencyType> currencyTypes = CurrencyType.getCurrencyTypeByGroup(CurrencyGroup.SIGN);
		for(CurrencyType currencyType : currencyTypes){
			all(playerCode, currencyType);
		}
	}

	static public Set<String> all(String playerCode, CurrencyType type) {
		try {
			RSet<String> rSet = touch(key(playerCode, type));
			Set<String> all = null;
			if (!rSet.isExists()){//从数据库加载
				List<SignPo> signPoList = SignDAO.getListByType(playerCode,type.getNumber());
				SignPo signPo = (signPoList != null && signPoList.size() > 0) ? signPoList.get(0) : null;

				if(signPo != null && !signPo.getValue().equals("")) {
					all = string2Set(signPo.getValue());
					for (String str : all) {//把数据放到redis内存里
						add(playerCode, type, Integer.parseInt(str));//把所有的都加入redis内存
					}
				}
				if (all == null) all = new HashSet<>();
			} else {
				all = rSet.readAll();
			}

			return all;
		} catch (RedisException e) {
			return new HashSet<>();
		}
	}

	static public boolean exist(String playerCode, CurrencyType type, int dataId) {
		try {
			return touch(key(playerCode, type)).contains(String.valueOf(dataId));
		} catch (RedisException e) {
			return false;
		}
	}

	static public void add(String playerCode, CurrencyType type, int dataId) throws RedisException {
		String lockKey = lockKey(playerCode, type);
		try {
			if (tryLock(lockKey)) {
				touch(key(playerCode, type)).add(String.valueOf(dataId));
			}
		} catch (InterruptedException e) {
		} finally {
			unlock(lockKey);
		}
	}

	static public void minus(String playerCode, CurrencyType type, int dataId) throws CurrencyNotEnoughException {
		if (!exist(playerCode, type, dataId)) {
			throw new CurrencyNotEnoughException(type, dataId);
		}
		String lockKey = lockKey(playerCode, type);
		try {
			if (tryLock(lockKey)) {
				touch(key(playerCode, type)).remove(String.valueOf(dataId));
			}
		} catch (Exception e) {
			throw new CurrencyNotEnoughException(type, dataId);
		} finally {
			unlock(lockKey);
		}
	}

	static private String lockKey(String playerCode, CurrencyType type) {
		return String.format("lock:%s", key(playerCode, type));
	}
	//数据归档到数据库
	public static void saveToDB(String playerCode) {
		try {
			//存储
			List<SignPo> signPoList = new ArrayList<>();

			ArrayList<CurrencyType> cts = CurrencyType.getCurrencyTypeByGroup(CurrencyGroup.SIGN);
			for(CurrencyType ct:cts){
				String key = key(playerCode, ct);
				if (touch(key).isExists()) {
					Set<String> all = touch(key).readAll();
					SignPo signPo = new SignPo();
					signPo.setPlayerCode(playerCode);
					signPo.setType(ct.getNumber());
					signPo.setValue(set2String(all));
					signPoList.add(signPo);
				}
			}
			SignDAO.replace(signPoList);
		}catch (Exception e){
			e.printStackTrace();
		}
	}

	//从redis移走数据
	public static void removeAllFromRedis(String playerCode) {
		try {
			//一次性全部清楚所有的
			ArrayList<CurrencyType> cts = CurrencyType.getCurrencyTypeByGroup(CurrencyGroup.SIGN);
			for(CurrencyType ct:cts) {
				touchBucket(key(playerCode,ct)).delete();
			}
		} catch (RedisException e) {
			e.printStackTrace();
		}
	}
}
